import { defineStore } from 'pinia'
import flvjs from 'flv.js'
import { apiPlayurl, apiHeartbeat } from '@renderer/api/bilibili'
import chalk from 'chalk'

export interface PlayerData {
  bvid: string
  cid: number
  cover: string
  title: string
  author: string
  duration: number
}

interface State {
  playerList: PlayerData[]
  isAudioPlay: boolean
  currentCid: number
  currentTime: number
  duration: number
  volume: number
}

type LoadAudioParams = {
  bvid: string
  cid: number
}

const audio = document.createElement('audio')
const blueBold = chalk.blueBright.bold
let player: flvjs.Player | null = null
const { cookies } = window.api

audio.addEventListener('play', () => {
  usePlayerStore().setIsAudioPlay(true)
})

audio.addEventListener('pause', () => {
  usePlayerStore().setIsAudioPlay(false)
})

audio.addEventListener('ended', () => {
  usePlayerStore().audioNext()
})

audio.addEventListener('loadedmetadata', () => {
  const duration = Math.floor(audio.duration)
  usePlayerStore().setDuration(duration)
  usePlayerStore().setCurrentTime(0)
})

let playbackPos = 0
audio.addEventListener('timeupdate', () => {
  const currentTime = Math.floor(audio.currentTime)
  usePlayerStore().setCurrentTime(currentTime)

  // 每隔10s上报播放进度
  if (Date.now() - playbackPos > 10 * 1000) {
    reportHeartbeat()
    playbackPos = Date.now()
  }
})

export const usePlayerStore = defineStore('player', {
  state: (): State => ({
    playerList: [],
    isAudioPlay: !audio.paused,
    currentCid: 0,
    currentTime: 0,
    duration: 0,
    volume: 100
  }),
  getters: {
    playingData: (state) => {
      const item = state.playerList.find((f) => f.cid === state.currentCid)
      return item
    }
  },
  actions: {
    pushPlayerList(obj: PlayerData) {
      const item = this.playerList.find((f) => f.cid === obj.cid)
      if (!item) {
        this.playerList.push(obj)
      }
    },
    setPlayerList(val: PlayerData[]) {
      this.playerList = val
    },
    setIsAudioPlay(val: boolean) {
      this.isAudioPlay = val
    },
    setCurrentCid(val: number) {
      this.currentCid = val
    },
    setCurrentTime(val: number) {
      this.currentTime = val
    },
    setDuration(val: number) {
      this.duration = val
    },
    setVolume(val: number) {
      audio.volume = val / 100
      this.volume = val
    },
    setAudioCurrentTime(val: number) {
      audio.currentTime = val
    },
    audioPause() {
      audio.pause()
    },
    audioPlay() {
      try {
        if (!audio.src) throw new Error('缺少播放地址')

        audio.play()
      } catch (e) {
        if (e instanceof Error) {
          console.error(e.message)
        } else {
          console.error(e)
        }

        if (this.playingData) {
          this.loadAudio(this.playingData)
        }
      }
    },
    async loadAudio(params: LoadAudioParams) {
      try {
        const { bvid, cid } = params
        const response = await apiPlayurl({
          fnval: 16,
          fourk: 1,
          bvid,
          cid
        })
        console.log(blueBold('播放地址===>'), response)
        const { durl, dash } = response.data
        // 老视频(flv)只会有durl字段
        const url: string = dash ? dash.audio[0].baseUrl : durl[0].url
        const urlObj = new URL(url)
        const type = urlObj.pathname.split('.').pop() || ''

        // 销毁旧的播放器实例，避免内存泄漏
        if (player) {
          player.pause()
          player.unload()
          player.detachMediaElement()
          player.destroy()
          player = null
        }

        player = flvjs.createPlayer({ type, url })
        player.attachMediaElement(audio)
        player.load()
        player.play()

        this.setVolume(this.volume)
        this.setCurrentCid(cid)
      } catch (e) {
        console.error(e)
      }
    },
    async audioNext() {
      const index = this.playerList.findIndex((f) => f.cid === this.currentCid)
      if (index === -1) return
      const next = index + 1
      if (next < this.playerList.length) {
        const nextData = this.playerList[next]
        await this.loadAudio({
          bvid: nextData.bvid,
          cid: nextData.cid
        })
      }
    },
    async audioPrev() {
      const index = this.playerList.findIndex((f) => f.cid === this.currentCid)
      if (index === -1) return
      const prev = index - 1
      if (prev >= 0) {
        const prevData = this.playerList[prev]
        await this.loadAudio({
          bvid: prevData.bvid,
          cid: prevData.cid
        })
      }
    }
  },
  persist: {
    /**
     * currentTime 当前时间，用来保持进度条无效
     * 在没有播放地址时，会触发loadedmetadata
     */
    pick: ['playerList', 'currentCid']
  }
})

async function reportHeartbeat() {
  const { playingData, currentTime } = usePlayerStore()
  if (!playingData) return
  const { cid, bvid } = playingData
  const csrf = await cookies('https://bilibili.com').getValue('bili_jct')
  const params = {
    bvid,
    cid,
    played_time: currentTime,
    csrf
  }
  await apiHeartbeat(params)
}
